import { ClusterNodeClient } from "../tsgfServer/cluster/ClusterNodeClient";
import { IRedisClient } from "../tsgfServer/redisHelper";
import { MatchRequestHelper } from "../tsgfServer/match/MatchRequestHelper";
import { AppMatchRequestMgr } from "./AppMatchRequestMgr";
import { IAppMatchTaskData } from "../tsgfServer/match/IAppMatchTaskData";
import { IMatchServerInfo } from "../tsgfServer/match/IMatchServerInfo";
import { IGameServerInfo } from "../hallClient/Models";
import { GameServerClusterMgr } from "../../gameServerCluster/GameServerClusterMgr";
import { arrWinner } from "../tsgf/Utils";
import { MatcherSingle } from "../tsgfServer/match/MatcherSingle";
import { RoomHelper } from "../tsgfServer/room/RoomHelper";
import { ICancelable } from "../tsgf/ICancelable";
import { ErrorCodes } from "../tsgf/Result";



/**匹配服务*/
export class BaseMatchServer extends ClusterNodeClient<IMatchServerInfo>{

    public matchRequestHelper: MatchRequestHelper;
    public appMatchRequestMgrs: Map<string, AppMatchRequestMgr> = new Map<string, AppMatchRequestMgr>();
    public getRedisClient: () => Promise<IRedisClient>;
    protected roomRegChangedCancel?: ICancelable;

    /**有新的应用匹配任务被接受后触发*/
    protected onNewAppMatchTask?: (appId: string, mgr: AppMatchRequestMgr) => void;
    /**应用匹配任务被取消后触发*/
    protected onCancelAppMatchTask?: (appId: string, mgr: AppMatchRequestMgr) => void;

    constructor(clusterServerUrl: string, serverNodeId: string, clusterKey: string,
        getRedisClient: () => Promise<IRedisClient>) {
        super(clusterServerUrl, serverNodeId, clusterKey, () => {
            return {
                serverId: serverNodeId,
                matchAppCount: this.appMatchRequestMgrs.size
            };
        });

        this.getRedisClient = getRedisClient;
        this.matchRequestHelper = new MatchRequestHelper(this.getRedisClient);


        //匹配服务的任务，就是负责处理应用的匹配，所以把应用ID当作任务ID使用
        this.onAssignTask = (taskId, taskData) => {
            let appId = taskId;
            let data = taskData as IAppMatchTaskData;
            let mgr = this.appMatchRequestMgrs.get(appId);
            if (!mgr) {
                mgr = new AppMatchRequestMgr(appId, this.matchRequestHelper, () => this.allotGameServer());
                this.appMatchRequestMgrs.set(appId, mgr);
            }
            mgr.matchers.clear();

            //先加入内置匹配器
            let matcher = new MatcherSingle();
            mgr.matchers.set(matcher.matcherKey, matcher);

            //再加入自定义匹配器
            //TODO: 未实现自定义匹配器的传递方案/动态加载方案

            this.onNewAppMatchTask?.call(this, appId, mgr);
        };
        this.onCancelTask = (taskId) => {
            let appId = taskId;

            let mgr = this.appMatchRequestMgrs.get(appId);
            if (!mgr) return;

            for (let reqs of mgr.allMatcherReqs.values()) {
                mgr.faildMatchRequests(reqs, '匹配服务器调整，请再次匹配', ErrorCodes.MatchRequestCancelled);
            }

            this.onCancelAppMatchTask?.call(this, appId, mgr);

        };
    }

    /**分配一个连接最少的游戏服务器*/
    protected async allotGameServer(): Promise<IGameServerInfo | null> {
        let nodeList = await GameServerClusterMgr.getServersFromRedis(this.getRedisClient);
        let minGameServer = arrWinner(nodeList,
            (winner, item) => winner.info.clientCount > item.info.clientCount ? item : winner);
        if (!minGameServer) return null;
        return minGameServer.info;
    }

    public async start(): Promise<void> {
        //订阅房间注册信息变更事件,更新到应用匹配管理下的房间注册信息缓存,方便匹配使用
        this.roomRegChangedCancel = await RoomHelper.startListenRoomRegInfoChanged(changedInfo => {
            let mgr = this.appMatchRequestMgrs.get(changedInfo.regInfo.appId);
            if (!mgr) return;
            mgr.roomRegInfoChanged(changedInfo);
        });
    }
    public async stop(): Promise<void> {
        await this.roomRegChangedCancel?.cancel();
        try {
            this.clusterClient?.disconnect();
        } catch { }
    }



}